import {
  AmbientLight,
  AxesHelper,
  Color,
  WebGLRenderer,
  Scene,
  PerspectiveCamera,
  Euler,
  Vector3,
  Quaternion,
} from "../3rdParty/three.js/build/three.module.js";

import * as THREE from "../3rdParty/three.js/build/three.module.js";

import { OrbitControls } from "../3rdParty/jsm/controls/OrbitControls.js";
import A3Object from "../A3Object.js";
import { isNumber } from "../common/Common.js";
import A3ObjectTypes from "../A3ObjectTypes.js";

const Axis = {
  X : new Vector3( 1, 0, 0 ),
  Y : new Vector3( 0, 1, 0 ),
  Z : new Vector3( 0, 0, 1 ),
} 


const defaultBgColor = 0x1982cc;

const meshes = [];

class Graphics {

  activeCamera = undefined;
  defaultCamera = undefined;

  constructor( mount ){
    this.mount = mount;
  }

  /**
   * 初始化图形世界
   * @param size 图像世界立方体大小
   */
  init( size = 10 ) {

    const renderer = newRenderer( this.mount );
    const scene = newScene( defaultBgColor );
    const camera = newCamera( 45, window.innerWidth/window.innerHeight, 0.1, size * 10 );
    camera.position.set( size, size, size );  // 默认全局摄像头位置

    const control = new OrbitControls( camera, renderer.domElement );
    control.target.set( 0, 0, 0 );
    console.log(control)

    camera.userData.control = control;

    const axes = new AxesHelper(1);
    scene.add(axes);

    const ambientLight = new AmbientLight( 0xffffff, 0.6 );
    scene.add(ambientLight)

    this.renderer = renderer;
    this.scene = scene;
    this.defaultCamera = camera;
    this.activeCamera = camera;
    this.control = control;

    // JUST FOR TEST
    // const mesh = new THREE.Mesh( new THREE.SphereGeometry(100) );
    // this.scene.add(mesh)

  }

  /**
   * 设置活动的相机或恢复默认相机
   * @param camera 为空时，恢复为默认相机
   */
  setActiveCamera( camera ) {

    if( !camera ) {

      this.activeCamera = this.defaultCamera;
      
    }
    else {

      this.activeCamera = camera.isA3Camera ? camera.camera : camera;
      
    }

  }

  resize() {

    const renderer = this.renderer;
    const camera = this.defaultCamera;

    // 总是全屏显示
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
   
    renderer.setSize( window.innerWidth, window.innerHeight );

  }

  update() {

    const renderer = this.renderer;
    const scene = this.scene;
    const camera = this.activeCamera;

    if( !renderer || !scene || !camera ) return;
    renderer.render( scene, camera ); 

    if( camera.userData.control ) {
      camera.userData.control.update();
    }

    if( camera !== this.defaultCamera ) {
      this.control.enabled = false;
    }
    else {
      this.control.enabled = true;
    }

  }

  add( obj ) {

    if( obj.isA3ObjectGroup ) {

      this.scene.add( obj.threeObject );
      meshes.push( obj.threeObject );

      for( var i = 0, il = obj.children.length; i < il; i++ ) {
        this.add( obj.children[i] );
      }

    }
    else {
      this.scene.add( obj.threeObject );
      meshes.push( obj.threeObject );
    }

  }

  clear() {
    
    for( var i = 0, il = meshes.length; i < il; i++ ) {
      this.scene.remove( meshes[i] );
    }

    meshes.length = 0;

  }

}

/**
 * 新建一个渲染器
 */
function newRenderer( mount ) {

  const renderer = new WebGLRenderer({ 
    alpha : true,
    preserveDrawingBuffer : true,
  });
  
  renderer.setPixelRatio( window.devicePixelRatio );
  renderer.setSize( window.innerWidth, window.innerHeight );
  renderer.shadowMap.enabled = true;

  if( mount ) {
    mount.appendChild( renderer.domElement );
  }

  return renderer;

}

/**
 * 新建一个场景
 */
function newScene( bgColor ) {

  const scene = new Scene();

  if( bgColor ) {
    scene.background = new Color( bgColor );
  }

  return scene;

}

/**
 * 新建一个相机
 */
function newCamera( fov=45, aspect=1, near=0.1, far=2000 ) {
  
  const camera = new PerspectiveCamera(
    fov, aspect, 
    near, far
  );
  
  return camera;

}


class A3GraphicsObject extends A3Object{

  isPhysical = false;

  update(){};

}

const CameraMovements = {
  Stop:0,
  Forward:1,  // z-
  Backward:2, // z+
  Left:3,     // x-
  Right:4,    // x+
  Up:5,       // y+
  Down:6,     // y-
  RotateLeft:7,    // ry+
  RotateRight:8,   // ry-
  LookUp:9,        // rx+
  LookDown:10,     // rx-
}

/**
 * 单目相机
 */
class A3MonocularCamera extends A3GraphicsObject{

  type=A3ObjectTypes.MonocularCamera;
  name=A3ObjectTypes.MonocularCamera;
  
  camera = undefined;
  cameraHeight = 0.0;
  cameraPitchRange = [ -Math.PI/6, Math.PI/ 6 ] ; // 俯仰角范围

  isA3Camera = true;
  
  fov = 60;
  aspect = 1;
  near = 0.01;
  far = 20000;

  // 移动控制
  tSpeed = 0.1;
  rSpeed = Math.PI / 180;
  direction = 0;  
  movementCmds=[];

  // 跳跃
  enableJump = false;
  jumpSpeed = 5;
  jumpDirection = 1;
  jumpMaxHeight = 100;

  constructor( x, y, z ) {
    super();

    x = isNumber(x) ? x : 0;
    y = isNumber(y) ? y : 180;
    z = isNumber(z) ? z : 0;

    const camera = new PerspectiveCamera( this.fov, this.aspect, this.near, this.far );
    this.camera = camera;

    this.threeObject.add( camera );
    this.position.set( x, y, z );
    this.threeObject.position.set( x, y, z );

    this.cameraHeight = y;

    for( var i = 0; i < Object.keys(CameraMovements);i++ ) {
      this.movementCmds.push(false);
    }

    this.initActions();

  }

  initActions() {
    this.addAction("move_forward", "KeyW", this.moveForward.bind(this));
  }

  stop() {

    for( var i = 0; i < Object.keys(CameraMovements);i++ ) {
      this.movementCmds[i] = false;
    }

  }

  moveForward( args ) {
    
    var enable = false;

    if( args.length === 1 ) {
      enable = args[0];
    }
    else if( args.length >= 2 ) {
      enable = args[0];
      this.tSpeed = args[1];
    }
    
    this.movementCmds[CameraMovements.Forward] = enable;

  }

  moveBackward( enable=true, speed=null ) {

    this.movementCmds[CameraMovements.Backward] = enable;

    if( isNumber(speed) ) {
      this.tSpeed = speed;
    }

  }

  rotateLeft(  enable=true, speed=null ) {

    this.movementCmds[CameraMovements.RotateLeft] = enable;

    if( isNumber(speed) ) {
      this.rSpeed = speed;
    }

  }

  rotateRight( enable=true, speed=null ) {

    this.movementCmds[CameraMovements.RotateRight] = enable;

    if( isNumber(speed) ) {
      this.rSpeed = speed;
    }

  }

  lookUp( enable=true, speed=null ) {

    this.movementCmds[CameraMovements.LookUp] = enable;

    if( isNumber(speed) ) {
      this.rSpeed = speed;
    }

  }

  lookDown( enable=true, speed=null ) {

    this.movementCmds[CameraMovements.LookDown] = enable;

    if( isNumber(speed) ) {
      this.rSpeed = speed;
    }

  }

  doJump( speed=null ) {

    this.enableJump = true;

    if( isNumber(speed) && speed > 0 ) {
      this.jumpSpeed = speed;
    }

    this.jumpDirection = 1;

  }

  toJson() {

    const data = super.toJson();

    data["camera"] = {
      fov:this.fov,
      aspect:this.aspect,
      near : this.near,
      far : this.far,
    }

    return data;

  }

  static fromJson( data, obj ) {

    if ( obj === null || obj === undefined ) {
      obj = new A3MonocularCamera();
    }

    super.fromJson( data, obj );
    
    return obj;

  }

  update() {

    const position = this.position;
    const quaternion = this.quaternion.clone();
    const cameraQuaternion = this.camera.quaternion;
    const tmpQuat = new Quaternion();
    const movement = new Vector3( 0, 0, 0 );
    const movementCmds = this.movementCmds;
    // 平移
    if( movementCmds[CameraMovements.Forward] ) {
      movement.z -= this.tSpeed;
    }
    if( movementCmds[CameraMovements.Backward] ) {
      movement.z += this.tSpeed;
    }

    movement.applyQuaternion(quaternion);
    position.x += movement.x ;
    position.z += movement.z ;

    // 旋转
    if( movementCmds[CameraMovements.RotateLeft] ) {
      tmpQuat.setFromAxisAngle( Axis.Y, this.rSpeed );
      quaternion.multiply( tmpQuat );
    }
    if( movementCmds[CameraMovements.RotateRight] ) {
      tmpQuat.setFromAxisAngle( Axis.Y, -this.rSpeed );
      quaternion.multiply( tmpQuat );
    }

    if( movementCmds[CameraMovements.LookUp] ) {
      
      if( this.camera.rotation.x < this.cameraPitchRange[1] ) {
        tmpQuat.setFromAxisAngle( Axis.X, this.rSpeed );
        cameraQuaternion.multiply( tmpQuat );
      }

    }
    if( movementCmds[CameraMovements.LookDown] ) {
      if( this.camera.rotation.x > this.cameraPitchRange[0] ) {
        tmpQuat.setFromAxisAngle( Axis.X, -this.rSpeed );
        cameraQuaternion.multiply( tmpQuat );
      }
    }



    if( this.enableJump ) {

      if( position.y >= this.cameraHeight + this.jumpMaxHeight) {
        this.jumpDirection = -1;
      }
      
      if( this.jumpDirection < 0 && (Math.abs(position.y - this.cameraHeight) < this.jumpSpeed) ){
        position.y = this.cameraHeight;
        this.enableJump = false;
        this.jumpDirection = 0;
      }
      else {
        position.y += this.jumpSpeed * this.jumpDirection;
      }
      
    }

    this.updateWorldTransform( position, quaternion );

  }

}

export default Graphics;

export{
  Axis,

  A3GraphicsObject,
  A3MonocularCamera,
}